home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Networking / StreamNOP1.0b2 / StreamNOP.c < prev    next >
Encoding:
Text File  |  1998-07-13  |  12.6 KB  |  424 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        StreamNOP.c
  3.  
  4.     Contains:    Stream module that does nothing.
  5.  
  6.     Written by:    Quinn "The Eskimo!"
  7.  
  8.     Copyright:    © 1997-1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.     You may incorporate this sample code into your applications without
  13.     restriction, though the sample code has been provided "AS IS" and the
  14.     responsibility for its operation is 100% yours.  However, what you are
  15.     not permitted to do is to redistribute the source as "DSC Sample Code"
  16.     after having made changes. If you're going to re-distribute the source,
  17.     we require that you make it clear in the source that the code was
  18.     descended from Apple Sample Code, but that you've made changes.
  19. */
  20.  
  21. /////////////////////////////////////////////////////////////////////
  22. // The OT debugging macros in <OTDebug.h> require this variable to
  23. // be set.
  24.  
  25. #ifndef qDebug
  26. #define qDebug    1
  27. #endif
  28.  
  29. /////////////////////////////////////////////////////////////////////
  30. // Determine whether this is going to be an instrumented build or not.
  31.  
  32. #ifndef INSTRUMENTATION_ACTIVE
  33.     #define INSTRUMENTATION_ACTIVE 0
  34. #else
  35.     #define INSTRUMENTATION_ACTIVE 1
  36. #endif
  37.  
  38. /////////////////////////////////////////////////////////////////////
  39. // Pick up all the standard OT module stuff.
  40.  
  41. #include <OpenTptModule.h>
  42.  
  43. /////////////////////////////////////////////////////////////////////
  44. // Pick up the OTDebugBreak and OTAssert macros.
  45.  
  46. #include <OTDebug.h>
  47.  
  48. /////////////////////////////////////////////////////////////////////
  49. // Pick up all the standard TPI/DLPI constants and structures.
  50.  
  51. #include <tihdr.h>
  52. #include <dlpi.h>
  53.  
  54. /////////////////////////////////////////////////////////////////////
  55. // Pick up Instrumentation SDK stuff.  We only do this if we're
  56. // actually instrumenting, so you don't even have to have the SDK
  57. // to compile the non-instumented version of the code.  If we're
  58. // not instrumenting, we compile a bunch of bogus macros that generally
  59. // compile to nothing.
  60.  
  61. #if INSTRUMENTATION_ACTIVE
  62.     #include <InstrumentationMacros.h>
  63. #else
  64.     #define TRACE_SETUP        long __junk
  65.     #define LOG_ENTRY(n)    if (0) { __junk ; }
  66.     #define LOG_EXIT        if (0) { __junk ; }
  67. #endif
  68.  
  69. /////////////////////////////////////////////////////////////////////
  70. // OTDebugStr is not defined in any OT header files, but it is
  71. // exported by the libraries, so we define the prototype here.
  72.  
  73. extern pascal void OTDebugStr(const char* str);
  74.  
  75. /////////////////////////////////////////////////////////////////////
  76. // Some simple routines we use in our various assertions.
  77.  
  78. static Boolean IsReadQ(queue_t* q)
  79.     // Returns true if q is the read queue of a queue pair.
  80. {
  81.     return ( (q->q_flag & QREADR) != 0 );
  82. }
  83.  
  84. static Boolean IsWriteQ(queue_t* q)
  85.     // Returns true if q is the write queue of a queue pair.
  86. {
  87.     return ( (q->q_flag & QREADR) == 0 );
  88. }
  89.  
  90. /////////////////////////////////////////////////////////////////////
  91. // Per-Stream information
  92.  
  93. // This structure is used to hold the per-stream data for the module.
  94. // While module's can use normal global variables to store real globals,
  95. // they must maintain their own per-stream data structures.  I use
  96. // mi_open_comm to allocate this data structure when the stream is
  97. // opened.  mi_open_comm stores the address of this data structure in the
  98. // read and write queue's q_ptr field, so the rest of the code
  99. // can get to it by calling the GetPerStreamData function.
  100.  
  101. enum {
  102.     kStreamNOPPerStreamDataMagic = 'NOOP'
  103. };
  104.  
  105. struct PerStreamData
  106. {
  107.     OSType                 magic;                // kStreamNOPPerStreamDataMagic = 'NOOP' for debugging
  108.     // Your per-stream data structures go here.
  109. };
  110. typedef struct PerStreamData PerStreamData, *PerStreamDataPtr;
  111.  
  112. static PerStreamDataPtr GetPerStreamData(queue_t* readOrWriteQ)
  113.     // You can pass both the read or the write queue to this routine
  114.     // because mi_open_comm sets up both q_ptr's to point to the
  115.     // queue local data.
  116.     //
  117.     // Note that, in order to avoid the overhead of a function call,
  118.     // you would normally use inline code (or a macro)
  119.     // to get your per-stream data instead of using a separate function.
  120.     // However I think the separate function makes things clearer.
  121.     // I also acts as a central bottleneck for my debugging code.
  122.     //
  123.     // Environment: any standard STREAMS entry point
  124. {
  125.     PerStreamDataPtr streamData;
  126.     
  127.     streamData = (PerStreamDataPtr) readOrWriteQ->q_ptr;
  128.  
  129.     OTAssert("GetPerStreamData: what streamData", streamData != nil);
  130.     OTAssert("GetPerStreamData: Bad magic", streamData->magic == kStreamNOPPerStreamDataMagic);
  131.     
  132.     return (streamData);
  133. }
  134.  
  135. // mi_open_comm and mi_close_comm (and also mi_detach and mi_close_detached)
  136. // use this global to store the list of open streams to this module.
  137.  
  138. static char* gStreamList = nil;
  139.  
  140. /////////////////////////////////////////////////////////////////////
  141. // Open routine
  142.  
  143. static int StreamNOPOpen(queue_t* rdq, dev_t* dev, int flag, int sflag, cred_t* creds)
  144.     // This routine is called by STREAMS when a new stream is connected to
  145.     // our module.  The bulk of the work here is done by the Mentat helper
  146.     // routine mi_open_comm.
  147.     //
  148.     // Environment: standard STREAMS entry point
  149. {
  150.     TRACE_SETUP;
  151.     int err;
  152.     PerStreamDataPtr streamData;
  153.  
  154.     LOG_ENTRY( "StreamNOP:StreamNOPOpen" );
  155.     
  156.     OTAssert("StreamNOPOpen: Not the read queue", IsReadQ(rdq) );
  157.  
  158.     OTDebugBreak("StreamNOPOpen");
  159.     
  160.     err = noErr;
  161.     
  162.     // If we already have per-stream data for this stream, the stream is being reopened.
  163.     // In that case, we can just return.
  164.     // Note that we can't call GetPerStreamData because it checks that streamData is not nil.
  165.     
  166.     if ( rdq->q_ptr != nil ) {
  167.         goto done;
  168.     }
  169.  
  170.     // Make sure we're being opened properly -- because we're a module we
  171.     // require a "module" open.  Other possibilities are the value 0 (used
  172.     // to open a specific minor device number (ie stream) on a device driver),
  173.     // and CLONEOPEN (used to open a new stream to a device number where you
  174.     // don't care what device number you get -- the typical behaviour for
  175.     // networking (as opposed to serial) devices).
  176.     
  177.     if ( (err == noErr) && (sflag != MODOPEN) ) {
  178.         err = ENXIO;
  179.     }
  180.     
  181.     // Use the mi_open_comm routine to allocate our per-stream data.  Then
  182.     // zero out the entire per-stream data record and fill out the fields
  183.     // we're going to need.
  184.     
  185.     if (err == noErr) {
  186.         err = mi_open_comm(&gStreamList, sizeof(PerStreamData), rdq, dev, flag, sflag, creds);
  187.         if ( err == noErr ) {
  188.             // Note that we can't call GetPerStreamData because the magic is not set up yet.
  189.             streamData = (PerStreamDataPtr) rdq->q_ptr;
  190.             
  191.             OTMemzero(streamData, sizeof(PerStreamData));
  192.             
  193.             streamData->magic = kStreamNOPPerStreamDataMagic;
  194.         }
  195.     }
  196.  
  197. done:
  198.     LOG_EXIT;
  199.     return (err);
  200. }
  201.  
  202. /////////////////////////////////////////////////////////////////////
  203. // Close routine
  204.  
  205. static int StreamNOPClose(queue_t* rdq, int flags, cred_t* credP)
  206.     // This routine is called by STREAMS when a stream is being
  207.     // disconnected from our module (ie closed).  The bulk of the work
  208.     // is done by the magic Mentat helper routine mi_close_comm.
  209.     //
  210.     // Environment: standard STREAMS entry point
  211. {
  212.     TRACE_SETUP;
  213.     #pragma unused(flags)
  214.     #pragma unused(credP)
  215.  
  216.     LOG_ENTRY( "StreamNOP:StreamNOPClose" );
  217.  
  218.     OTAssert("StreamNOPClose: Not the read queue", IsReadQ(rdq) );
  219.  
  220.     (void) mi_close_comm(&gStreamList, rdq);
  221.  
  222.     LOG_EXIT;
  223.     return (0);
  224. }
  225.  
  226. /////////////////////////////////////////////////////////////////////
  227.  
  228. enum {
  229.     kNoPrimitive = -1
  230. };
  231.  
  232. static long GetPrimitive(mblk_t* mp)
  233.     // GetPrimitive gets the TPI/DLPI primitive out of a message block.
  234.     // It returns kNoPrimitive if the message block is of the wrong
  235.     // type or there is no primitive.
  236.     //
  237.     // Environment: any standard STREAMS entry point
  238. {
  239.     if ((mp->b_datap->db_type == M_PROTO || mp->b_datap->db_type == M_PCPROTO) && MBLK_SIZE(mp) >= sizeof(long) ) {
  240.         return ( ( (union T_primitives*) mp->b_rptr)->type );
  241.     } else {
  242.         return ( kNoPrimitive );
  243.     }
  244. }
  245.  
  246. /////////////////////////////////////////////////////////////////////
  247. // Write-side put routine
  248.  
  249. static int StreamNOPWritePut(queue_t* q, mblk_t* mp)
  250.     // This routine is called by STREAMS when it has a message for our
  251.     // module from upstream.  Typically, this routine is a big case statement
  252.     // that dispatches to our various message handling routines.  However, the 
  253.     // function of this stream module is to pass through all messages unchanged,
  254.     // so the case statement is not very exciting.
  255.     //
  256.     // Environment: standard STREAMS entry point
  257. {
  258.     TRACE_SETUP;
  259.     PerStreamDataPtr streamData;
  260.     
  261.     LOG_ENTRY( "StreamNOP:StreamNOPWritePut" );
  262.  
  263.     OTAssert("StreamNOPWritePut: Not the write queue", IsWriteQ(q) );
  264.  
  265.     // OTDebugBreak("StreamNOPWritePut: Entered");
  266.     
  267.     streamData = GetPerStreamData(q);
  268.  
  269.     switch ( GetPrimitive(mp) ) {
  270.         default:
  271.             putnext(q, mp);
  272.             break;
  273.     }
  274.     
  275.     LOG_EXIT;
  276.     
  277.     return 0;
  278. }
  279.  
  280. /////////////////////////////////////////////////////////////////////
  281. // Read-side put routine
  282.  
  283. static int StreamNOPReadPut(queue_t* q, mblk_t* mp)
  284.     // This routine is called by STREAMS when it has a message for our
  285.     // module from downstream.  Typically, this routine is a big case statement
  286.     // that dispatches to our various message handling routines.  However, the 
  287.     // function of this stream module is to pass through all messages unchanged,
  288.     // so the case statement is not very exciting.
  289.     //
  290.     // Environment: standard STREAMS entry point
  291. {
  292.     TRACE_SETUP;
  293.     PerStreamDataPtr streamData;
  294.     
  295.     LOG_ENTRY( "StreamNOP:StreamNOPReadPut" );
  296.  
  297.     OTAssert("StreamNOPReadPut: Not the read queue", IsReadQ(q) );
  298.  
  299.     // OTDebugBreak("StreamNOPReadPut: Entered");
  300.     
  301.     streamData = GetPerStreamData(q);
  302.  
  303.     switch ( GetPrimitive(mp) ) {
  304.         default:
  305.             putnext(q, mp);
  306.             break;
  307.     }
  308.     
  309.     LOG_EXIT;
  310.     
  311.     return 0;
  312. }
  313.  
  314. /////////////////////////////////////////////////////////////////////
  315. // Static Declaration Structures
  316.  
  317. static struct module_info gModuleInfo =  
  318. {
  319.     9992,                        // Module Number, only useful for debugging
  320.     "StreamNOP",                // Name of module
  321.     0,                            // Minimum data size
  322.     INFPSZ,                        // Maximum data size
  323.     16384,                        // Hi water mark for queue
  324.     4096                        // Lo water mark for queue
  325. };
  326.  
  327. static struct qinit gReadInit = 
  328. {
  329.     StreamNOPReadPut,        // Put routine for "incoming" data
  330.     nil,                        // Service routine for "incoming" data
  331.     StreamNOPOpen,            // Our open routine
  332.     StreamNOPClose,         // Our close routine
  333.     nil,                        // No admin routine
  334.     &gModuleInfo                // Our module_info
  335. };
  336.  
  337. static struct qinit gWriteInit =
  338. {
  339.     StreamNOPWritePut,        // Put routine for client data
  340.     nil,                        // Service routine for client data
  341.     nil,                        // open  field only used in read-side structure
  342.     nil,                        // close field only used in read-side structure
  343.     nil,                        // admin field only used in read-side structure
  344.     &gModuleInfo                // Our module_info
  345. };
  346.  
  347. static struct streamtab theStreamTab = 
  348. {
  349.     &gReadInit,                    // Our read-side qinit structure
  350.     &gWriteInit,                // Our write-side qinit structure
  351.     0,                            // We are not a mux, so set this to nil
  352.     0                            // We are not a mux, so set this to nil
  353. };
  354.  
  355. /////////////////////////////////////////////////////////////////////
  356. // Macintosh-specific Static Structures
  357.  
  358. static struct install_info theInstallInfo =
  359. {
  360.     &theStreamTab,            // Stream Tab pointer
  361.     kOTModIsModule + kOTModUpperIsTPI + kOTModIsFilter,
  362.                             // Tell OT that we are a driver, not a module
  363.     SQLVL_MODULE,            // Synchronization level, module level for the moment
  364.     0,                        // Shared writer list buddy
  365.     0,                        // Open Transport use - always set to 0
  366.     0                        // Flag - always set to 0
  367. };
  368.  
  369. // Prototypes for the exported routines below.
  370.  
  371. extern Boolean InitStreamModule(void *portInfo);
  372. extern void TerminateStreamModule(void);
  373. extern install_info* GetOTInstallInfo();
  374.  
  375. #pragma export list GetOTInstallInfo, InitStreamModule, TerminateStreamModule
  376.  
  377. // Export entry point
  378.  
  379. extern Boolean InitStreamModule(void *portInfo)
  380.     // Initialises the module before the first stream is opened.
  381.     // Should return true if the module has started up correctly.
  382.     //
  383.     // Environment: Always called at SystemTask time.
  384. {    
  385.     TRACE_SETUP;
  386.     #pragma unused(portInfo)
  387.     Boolean result;
  388.     
  389.     OTDebugBreak("StreamNOP: InitStreamModule");
  390.     
  391.     LOG_ENTRY( "StreamNOP:InitStreamModule" );
  392.  
  393.     result = true;
  394.     
  395.     LOG_EXIT;
  396.     return (result);
  397. }
  398.  
  399. extern void TerminateStreamModule(void)
  400.     // Shuts down the module after the last stream has been
  401.     // closed.
  402.     //
  403.     // Environment: Always called at SystemTask time.
  404. {
  405.     TRACE_SETUP;
  406.     
  407.     LOG_ENTRY( "StreamNOP:TerminateStreamModule" );
  408.     
  409.     // It's an excellent idea to have the following in your code, just to make
  410.     // sure you haven't left any streams open before you quit.  In theory, OT
  411.     // should not call you until the last stream has been closed, but in practice
  412.     // this can happen if you use mi_detach to half-close a stream.
  413.     
  414.     OTAssert("TerminateStreamModule: Streams are still active", gStreamList == nil);
  415.  
  416.     LOG_EXIT;
  417. }
  418.  
  419. extern install_info* GetOTInstallInfo()
  420.     // Return pointer to install_info to STREAMS.
  421. {
  422.     return &theInstallInfo;
  423. }
  424.